#include "acl_stdafx.hpp"
#ifndef ACL_PREPARE_COMPILE
#include "redis/redis_client_cluster.hpp"
#include "redis/redis.hpp"
#include "session/redis_session.hpp"
#endif

namespace acl
{

redis_session::redis_session(redis_client_cluster& cluster, size_t max_conns,
	time_t ttl /* = 0 */, const char* sid /* = NULL */)
	: session(ttl, sid)
	, cluster_(cluster)
{
	command_ = NEW redis;
	command_->set_cluster(&cluster_, max_conns == 0 ? 128 : max_conns);
}

redis_session::~redis_session()
{
	delete command_;
	std::map<string, session_string*>::iterator it;
	for (it = buffers_.begin(); it != buffers_.end(); ++it)
		delete it->second;
}

bool redis_session::set(const char* name, const char* value)
{
	return set(name, value, strlen(value));
}

bool redis_session::set(const char* name, const void* value, size_t len)
{
	const char* sid = get_sid();
	if (sid == NULL || *sid == 0)
		return false;

	command_->clear();
	if (command_->hset(sid, name, (const char*) value, len) < 0)
		return false;
	time_t ttl = get_ttl();
	if (ttl > 0)
		return set_timeout(ttl);
	return true;
}

const session_string* redis_session::get_buf(const char* name)
{
	command_->clear();
	const char* sid = get_sid();
	if (sid == NULL || *sid == 0)
		return NULL;

	// 先尝试从缓存池中获得一个缓冲区，如果没有合适的，则创建新的缓冲区对象
	// 并将之加入至缓冲池中，以备下次重复查询相同属性时使用

	session_string* ss;
	std::map<string, session_string*>::iterator it = buffers_.find(name);
	if (it == buffers_.end())
	{
		ss = NEW session_string;
		buffers_[name] = ss;
	}
	else
	{
		ss = it->second;
		ss->clear();
	}

	if (command_->hget(sid, name, *ss) == false)
		return NULL;
	return ss;
}

bool redis_session::del(const char* name)
{
	const char* sid = get_sid();
	if (sid == NULL || *sid == 0)
		return false;

	command_->clear();
	return command_->hdel(sid, name) >= 0 ? true : false;
}

bool redis_session::set_attrs(const std::map<string, session_string>& attrs)
{
	const char* sid = get_sid();
	if (sid == NULL || *sid == 0)
		return false;

	command_->clear();
	if (command_->hmset(sid, (const std::map<string, string>&) attrs) == false)
		return false;

	time_t ttl = get_ttl();
	if (ttl > 0)
		return set_timeout(ttl);
	else
		return true;
}

bool redis_session::get_attrs(std::map<string, session_string>& attrs)
{
	attrs_clear(attrs);
	const char* sid = get_sid();
	if (sid == NULL || *sid == 0)
		return false;

	command_->clear();
	return command_->hgetall(sid, (std::map<string, string>&) attrs);
}

bool redis_session::get_attrs(const std::vector<string>& names,
	std::vector<session_string>& values)
{
	values.clear();
	const char* sid = get_sid();
	if (sid == NULL || *sid == 0)
		return false;

	command_->clear();
	std::vector<string> vals;
	if (command_->hmget(sid, names, &vals) == false)
		return false;

	for (std::vector<string>::const_iterator cit = vals.begin();
		cit != vals.end(); ++cit)
	{
		values.push_back(*cit);
	}

	return true;
}

bool redis_session::remove()
{
	const char* sid = get_sid();
	if (sid == NULL || *sid == 0)
		return false;

	command_->clear();
	return command_->del(sid) >= 0 ? true : false;
}

bool redis_session::set_timeout(time_t ttl)
{
	const char* sid = get_sid();
	if (sid == NULL || *sid == 0)
		return false;

	command_->clear();
	return command_->expire(sid, (int) ttl) > 0 ? true : false;
}

} // namespace acl
